#pragma once
#ifndef M6502_H
#define M6502_H

////////////////////////////////////////////////////////////////////////////////////////////////////

#include "Commons.h"
#include <map>
#include <iostream>

////////////////////////////////////////////////////////////////////////////////////////////////////

class M6502 {
    public:
                            M6502               ();
        virtual             ~M6502              ();
        unsigned char       Fetch               ();
        int                 Execute             ( unsigned char );
        void                HandleNMI           ();

    // Setters
        void                SetPC               ( unsigned short value )                            { m_PC.W = value; }
        void                SetRead             ( unsigned char (*value)(unsigned short) )          { m_Read = value; }
        void                SetWrite            ( void (*value)(unsigned short, unsigned char) )    { m_Write = value; }

    private:
        void                                                        Debug           ( char[], int, std::string );
        unsigned char                                               Peek            ( int );
        unsigned char                                               JoinFlags       ()const;
        void                                                        StackPush       ( unsigned char );
        unsigned char                                               StackPop        ();
        unsigned short                                              SolveAddress    ( int );
        void                                                        OP_ADC          ( int );
        void                                                        OP_AND          ( int );
        void                                                        OP_ASL          ( int );
        void                                                        OP_BIT          ( int );
        void                                                        OP_BCC          ( int );
        void                                                        OP_BCS          ( int );
        void                                                        OP_BEQ          ( int );
        void                                                        OP_BMI          ( int );
        void                                                        OP_BNE          ( int );
        void                                                        OP_BPL          ( int );
        void                                                        OP_BVC          ( int );
        void                                                        OP_BVS          ( int );
        void                                                        OP_CLC          ( int );
        void                                                        OP_CLD          ( int );
        void                                                        OP_CLI          ( int );
        void                                                        OP_CLV          ( int );
        void                                                        OP_CMP          ( int );
        void                                                        OP_CPX          ( int );
        void                                                        OP_CPY          ( int );
        void                                                        OP_DEC          ( int );
        void                                                        OP_DEX          ( int );
        void                                                        OP_DEY          ( int );
        void                                                        OP_EOR          ( int );
        void                                                        OP_INC          ( int );
        void                                                        OP_INX          ( int );
        void                                                        OP_INY          ( int );
        void                                                        OP_JMP          ( int );
        void                                                        OP_JSR          ( int );
        void                                                        OP_LDA          ( int );
        void                                                        OP_LDX          ( int );
        void                                                        OP_LDY          ( int );
        void                                                        OP_LSR          ( int );
        void                                                        OP_NOP          ( int );
        void                                                        OP_ORA          ( int );
        void                                                        OP_PHA          ( int );
        void                                                        OP_PHP          ( int );
        void                                                        OP_PLA          ( int );
        void                                                        OP_PLP          ( int );
        void                                                        OP_ROL          ( int );
        void                                                        OP_ROR          ( int );
        void                                                        OP_RTI          ( int );
        void                                                        OP_RTS          ( int );
        void                                                        OP_SBC          ( int );
        void                                                        OP_SEC          ( int );
        void                                                        OP_SED          ( int );
        void                                                        OP_SEI          ( int );
        void                                                        OP_STA          ( int );
        void                                                        OP_STX          ( int );
        void                                                        OP_STY          ( int );
        void                                                        OP_TAX          ( int );
        void                                                        OP_TAY          ( int );
        void                                                        OP_TSX          ( int );
        void                                                        OP_TXA          ( int );
        void                                                        OP_TXS          ( int );
        void                                                        OP_TYA          ( int );

        M6502_REGISTERS                                             m_Reg;
        PAIR_REGISTER                                               m_PC;
        unsigned char                                               m_SP;
        M6502_FLAGS                                                 m_Flag;
        int                                                         m_Cycles;
        unsigned char                                               ( *m_Read )     ( unsigned short );
        void                                                        ( *m_Write )    ( unsigned short, unsigned char );
        std::map<unsigned char, void (M6502::*)(int)>    m_OPFunc;
        std::map<unsigned char, int>                     m_OPMode;
        std::map<unsigned char, int>                                m_OPCycles;
        std::map<unsigned char, std::string>                        m_OPName;
};

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
